# -*- coding: utf-8 -*-
import base64
import json
from collections import OrderedDict

import requests
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from django.conf import settings

from async import async_job
from common.channel.pay import check_channel_order
from common.order import db as order_db
from common.order.model import PAY_STATUS
from common.utils import track_logging
from common.utils.exceptions import ParamError

_LOGGER = track_logging.getLogger(__name__)

APP_CONF = {
    '1181120142838006': {  # dwc 支付宝 10---5000 费率2.3
        'gateway': 'http://api.fukupay.com/v2',
        'query_gateway': 'http://api.fukupay.com/v2',
        'pub_key': """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtWMwkB4QZq+ougRXfxcF
b9EnbZiGkqMvcJgievPDTbYln5RDo4gDYE7PxWHdMoV0B8q+X3kn5hTx5hWpsFpP
fY0Ck1sSG3iQGLfhDMWlqv4MaMihojD6yMkm8bG55EaqRZzVVcz8MOqP7HuGeSwj
wC2fJJbsjTdDbBoz7nIVn8a5j4yoAuMTRlbtiG0YkcG0sG/Idma9HlwhoqIp8gkw
caAXlVn7IyZG7+AV7nPCADemFcKJtCHAlVQNZkF1gKsXAH1TJu9dFUf/UYolOtlo
/ldmOM8i/ssbZ6fIYZPMd9wMd+0CAm9bkhCmw7WeCVUqZViC0QnDlyEeMhKHXj1L
AQIDAQAB
-----END PUBLIC KEY-----
""",
        'pri_key': """-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1YzCQHhBmr6i6
BFd/FwVv0SdtmIaSoy9wmCJ688NNtiWflEOjiANgTs/FYd0yhXQHyr5feSfmFPHm
FamwWk99jQKTWxIbeJAYt+EMxaWq/gxoyKGiMPrIySbxsbnkRqpFnNVVzPww6o/s
e4Z5LCPALZ8kluyNN0NsGjPuchWfxrmPjKgC4xNGVu2IbRiRwbSwb8h2Zr0eXCGi
oinyCTBxoBeVWfsjJkbv4BXuc8IAN6YVwom0IcCVVA1mQXWAqxcAfVMm710VR/9R
iiU62Wj+V2Y4zyL+yxtnp8hhk8x33Ax37QICb1uSEKbDtZ4JVSplWILRCcOXIR4y
EodePUsBAgMBAAECggEAHEC277u/Ej+KKG9EsacEUcZiPc/kJjME0KThugT+Bry4
X4LYhkBJRlcARd5YdeYTjKMnw/c7H7tjclMteyqV9xhfrlQhHeZJi5AYncSraVbo
1+loQ7sdVOkAB+WG7ueS3gTvtc2X+oaOpGcZKwaVCvoQL8LSVayl89ChBiL++0PV
qhm0A/E3K38J0NtW6KBJfrprPc3lN8mGiwGeHmPhevTLFtv4aj2zKrZ3vQXuhyEW
l4X9Bc3z+elLVC6TmGD83G0LEJLiVWHvoi34FSMUS9NY9ftIHNmR3pvKfIKpoOnd
QjeNvJ2HkfIbBgqYaG8uIdj5LU2fv2g3jvzwilNIAQKBgQDjNZl4gkFk2R3Gr3NB
32JAQSDzCFM7b3+dkxx/Uuh3HwiZhUHMqXrhXEjXvdcDO6vrphlolDLsKqU9QBx3
p1d0OeUd0JhBtS9sze8XHCbJf9j0ZrtjGiN/0iOzbWbwLfLxasC2BBL3CbnfZ15Y
OpIAy2HPuCywe/YcX4HuFKh/yQKBgQDMXy6eTr6xuBofOfM5Tke6RxWbCrzCiy5p
3Y/eyM7fEdUiSOU9kTCtl1yZL95C2p/ZHeP/7RmExW9IlqYAFP+kchU2MxTTvq9R
aGFrIgdzyO96agvFtUO6RocQVPLtDTvPUA/PGV0XGo3TmGNZZKQZ7T8M0hKD7tSQ
FkOR4fY9eQKBgQDctmGaRfYecCbTrfXppIU948aNL6Yi04IFYTXKnZBCvzvMXj14
AZ7jspD0Om7Wri2ooVaHV4dMEXUo1dGRjlaPCfp+hvaQxeAG8tlx+p/XF8F6UR1w
/KBFd63Ei972K7yXNdt0NOrzXVhZI4HrdSIFcYxXixKmchS2pTSDQUAZuQKBgQCE
2QZrv5Iz4hGQ5NGXGayEiPqhauxipaiJBo4j6nKXDHd4LtxdFgkHflGh/jzDRmwL
7WMtFIm3BcQd8ld7zCqVUdc6ASBzuAsspuZUhq1DdYU+FLsMTJT2/CuF0UKMF0Me
stNj8v/RKeCxf+hszn/hnpeSlOeWPWSNOPu5U6IGOQKBgHKM2i+emTbm3YzxTvRe
P6M3qZ9poiMd1fnTs6H8MhYx4PlpZiKB9MdiKhw+LG85/6nmO5/Rvik00XZKAQIP
L6hepw2tPIe6vv7c3tiJy8Zs0jZ6UZAL47Ojl9Lo52iKeTim7D46pTPrj1syTe4A
+rETVWrwFWA4ZSOjNoNYwaG1
-----END PRIVATE KEY-----
""",
        'maku_pub': """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+UvlgWjOf0JXtgiYK9/2BiaLzp
Zc9dW3/btrGCDMUZrJ0+eFioA5SsMuqlVR3DpYHUTdRgAWdv3NBk3s6AfmjW8nWzZ
aRuJOyxk8fVzu44nObtZxc3oO9jM3YYU7yPgpWZOHGp8CCQOOPZafmZfMJXhZ6cup
KsYz9gErEU0BjCwIDAQAB
-----END PUBLIC KEY-----""",
    },
}


def _get_gateway(mch_id):
    return APP_CONF[mch_id]['gateway']


def _get_query_gateway(mch_id):
    return APP_CONF[mch_id]['query_gateway']


def _get_pub_key(mch_id):
    return APP_CONF[mch_id]['pub_key']


def _get_pri_key(mch_id):
    return APP_CONF[mch_id]['pri_key']


def _get_makupub_key(mch_id):
    return APP_CONF[mch_id]['maku_pub']


def _gen_sign(message, the_key):
    key = RSA.importKey(the_key)
    h = SHA.new(message)
    signer = Signature_pkcs1_v1_5.new(key)
    signature = signer.sign(h)
    return base64.b64encode(signature)


def _verify_sign(data, signature, key):
    key = RSA.importKey(key)
    h = SHA.new(data)
    verifier = Signature_pkcs1_v1_5.new(key)
    if verifier.verify(h, base64.b64decode(signature)):
        return True
    return False


def generate_rsa_sign_str(parameter):
    s = ''
    for k in sorted(parameter.keys()):
        s += '%s=%s&' % (k.encode('utf8'), parameter[k].encode('utf8'))
    _LOGGER.info('makupay rsa_sign_str: %s', s[:-1])
    return s[:-1]


def _get_pay_type(service):
    if service == 'alipay':
        return 'alipayfixed_qrcode'
    return 'alipayfixed_qrcode'


def create_charge(pay, pay_amount, info):
    service = info.get('service')
    app_id = info['app_id']
    parameter_dict = OrderedDict((
        ('partner_id', '10803700000000597819'),
        ('service', 'com.order.Unified.Pay'),
        ('sign_type', 'RSA'),
        ('rand_str', str(pay.id)),
        ('version', 'v1'),
        ('merchant_no', app_id),
        ('merchant_order_sn', str(pay.id)),
        ('paychannel_type', _get_pay_type(service)),
        ('trade_amount', str(int(pay_amount * 100))),
        ('merchant_notify_url',
         '{}/pay/api/{}/makupay/{}/'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)),
        ('ord_name', 'charge'),
        ('interface_type', '1'),
    ))
    sign_str = generate_rsa_sign_str(parameter_dict)
    parameter_dict['sign'] = _gen_sign(sign_str, _get_pri_key(app_id))
    _LOGGER.info("makupay requests data: %s", json.dumps(parameter_dict))
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
    _LOGGER.info("makupay response %s, %s", response.status_code, response.text)
    return {'charge_info': json.loads(response.text)['data']['out_pay_url']}


def verify_notify_sign(params, pub_key):
    sign = params['sign']
    params.pop('sign')
    sign_str = generate_rsa_sign_str(params)
    if not _verify_sign(sign_str, sign, pub_key):
        _LOGGER.info("makupay sign: %s, sign_str : %s", sign, sign_str)
        raise ParamError('sign not pass, data: %s' % params)


# SUCCESS
def check_notify_sign(request, app_id):
    maku_key = _get_makupub_key(app_id)
    data = dict(request.POST.iteritems())
    _LOGGER.info("makupay notify data: %s", data)
    verify_notify_sign(data, maku_key)
    pay_id = data['merchant_order_sn']
    if not pay_id:
        _LOGGER.error("fatal error, out_trade_no not exists, data: %s" % data)
        raise ParamError('makupay event does not contain pay ID')

    pay = order_db.get_pay(int(pay_id))
    if not pay:
        raise ParamError('pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ParamError('pay %s has been processed' % pay_id)

    mch_id = pay.mch_id
    trade_status = data[u'pay_status']
    trade_no = data[u'order_sn']
    total_fee = float(data[u'trade_amount']) / 100.0
    extend = {
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee
    }

    check_channel_order(pay_id, total_fee, app_id)

    if trade_status == '1' and total_fee > 0.0:
        _LOGGER.info('makupay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
        order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)
        # async notify
        async_job.notify_mch(pay_id)


def query_charge(pay_order, app_id):
    pay_id = pay_order.id
    parameter_dict = OrderedDict((
        ('partner_id', '10803700000000597819'),
        ('service', 'com.order.Trade.Query'),
        ('sign_type', 'RSA'),
        ('rand_str', str(pay_id)),
        ('version', 'v1'),
        ('merchant_no', app_id),
        ('merchant_order_sn', str(pay_id)),
    ))
    sign_str = generate_rsa_sign_str(parameter_dict)
    parameter_dict['sign'] = _gen_sign(sign_str, _get_pri_key(app_id))
    _LOGGER.info("makupay query req data: %s", json.dumps(parameter_dict))
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_query_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
    _LOGGER.info("makupay query rsp code: %s, data: %s", response.status_code, response.text)

    if response.status_code == 200:
        data = json.loads(response.text)
        trade_status = data['data']['pay_status']
        total_fee = float(data['data']['trade_amount']) / 100.0
        trade_no = data['data']['order_sn']
        extend = {
            'trade_status': trade_status,
            'trade_no': trade_no,
            'total_fee': total_fee
        }

        if trade_status == '1':
            check_channel_order(pay_id, total_fee, app_id)

            _LOGGER.info('makupay query order success, mch_id:%s pay_id:%s' % (pay_order.mch_id, pay_id))
            order_db.add_pay_success(pay_order.mch_id, pay_id, total_fee, trade_no, extend)
            async_job.notify_mch(pay_order.id)
    else:
        _LOGGER.warn('makupay data error, status_code: %s', response.status_code)
